package com.bytebuddytest.custominstrumentation;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveTypeAwareAssigner;
import net.bytebuddy.matcher.ElementMatchers;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author yutianhong
 * @version 1.0
 * @since 2023/12/28 16:14
 */
public class ManipulationTest {

    @Test
    public void testCustomMethod() throws InstantiationException, IllegalAccessException {
        int ret = new ByteBuddy()
                .subclass(SumExample.class)
                .method(ElementMatchers.named("calculate"))
                .intercept(SumImplementation.INSTANCE)
                .make()
                .load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .calculate();
        ByteBuddyAgent.install();
        Assert.assertSame(60, ret);
    }

    @Test
    public void testCustomAssigner() throws InstantiationException, IllegalAccessException {
        String string = new ByteBuddy()
                .subclass(Object.class)
                .method(ElementMatchers.named("toString"))
                .intercept(FixedValue.value(42)
                        .withAssigner(new PrimitiveTypeAwareAssigner(ToStringAssigner.INSTANCE),
                                Assigner.Typing.STATIC))
                .make()
                .load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .toString();
        Assert.assertEquals("42", string);
    }

    public static class ToStringInterceptor {
        public static String makeString(@StringValue("Hello!") String value) {
            return value;
        }
    }

    @Test
    public void testCustomBinder() throws InstantiationException, IllegalAccessException {
        String string = new ByteBuddy()
                .subclass(Object.class)
                .method(ElementMatchers.named("toString"))
                .intercept(MethodDelegation.withDefaultConfiguration()
                        .withBinders(StringValueBinder.INSTANCE)
                        .to(ToStringInterceptor.class))
                .make()
                .load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .toString();
        Assert.assertEquals("Hello!", string);
    }
}